package cz.vse.po1715.lode.net.obecne;

import java.nio.*;
import java.nio.channels.*;

/*******************************************************************************
 * Instance třídy {@code NIOUtils} představují Misc utility funkce ke
 * zjednodušení transakcí událostí s NIO kanály a buffery
 *
 * @author    Dominik KOSTKA
 * @version   0.00.000
 */
public class NIOUtils
{
//== KONSTANTNÍ ATRIBUTY TŘÍDY =================================================
//== PROMĚNNÉ ATRIBUTY TŘÍDY ===================================================
//== STATICKÝ INICIALIZAČNÍ BLOK - STATICKÝ KONSTRUKTOR ========================
//== KONSTANTNÍ ATRIBUTY INSTANCÍ ==============================================
//== PROMĚNNÉ ATRIBUTY INSTANCÍ ================================================
//== PŘÍSTUPOVÉ METODY VLASTNOSTÍ TŘÍDY ========================================
//== OSTATNÍ NESOUKROMÉ METODY TŘÍDY ===========================================

    /**
     * Nejprve zapíše hlavičku a pak
     * událost do poskytnutého ByteBufferu
     * v rámci příprav na zápis do kanálu
     */
    public static void pripravBuffer(IHerniUdalost udalost, ByteBuffer cil) {
	
        // příprava na zápis hlavičky
	cil.clear();
        //zápis id klienta (hráče) do hlavičky
	cil.putInt(udalost.getIdHrac().hashCode());

	// zápis názvu hry do hlavičky
        if (udalost.getNázevHry() != null)
	    cil.putInt(udalost.getNázevHry().hashCode());
	else
	    cil.putInt(0);

        int pozice = cil.position();

        // rezervovaný prostor pro velikost herní události
        cil.putInt(0);

        // zapíše událost do zadaného cílového bufferu a vrátí její velikost
	int velikostUdálosti = udalost.zapiš(cil);

//	 nastaví velikost herní události do cílového bufferu
	cil.putInt(pozice, velikostUdálosti);

	// přípraví Buffer k zápisu události do klientského kanálu
	cil.flip();
    }


    /**
     * zapíše obsah zdrojového ByteBufferu do poskytnutého klientského kanálu
     */
    public static void zapišDoKanálu(SocketChannel kanál, ByteBuffer zdroj) {
	long zapsáno = 0;
	long kZapsání = zdroj.remaining();

	// opakuje volání metody kanál.write() pro případ,
        // že by herní událost nebyla do kanálu zapsána najednou
	try {
	    while (zapsáno != kZapsání) {
		zapsáno += kanál.write(zdroj);

		try {
		    Thread.sleep(Konstanty.ZÁPIS_DO_KANÁLU_SPÁNEK);
		}
		catch (InterruptedException e) {}
	    }
	}
	catch (ClosedChannelException cce) {
	}
	catch (Exception e) {
	}

	// připraví Buffer pro zápis další události
	zdroj.rewind();
    }

    /**
     * zapíše String do ByteBufferu,
     * Stringu předchází short integer reprezentující jeho délku
     */
    public static void zapišString(ByteBuffer cíl, String str) {
	if (str == null) {
	    cíl.putShort((short)0);
	}
	else {
	    cíl.putShort((short)str.length());
	    cíl.put(str.getBytes());
	}
    }

    /**
     * String, který byl zapsán metodou zapišString, načte z ByteBufferu
     * 
     */
    public static String getStr(ByteBuffer zdroj) {
	short len = zdroj.getShort();
	if (len == 0) {
	    return null;
	}
	else {
	    byte[] b = new byte[len];
	    zdroj.get(b);
	    return new String(b);
	}
    }


//##############################################################################
//== KONSTRUKTORY A TOVÁRNÍ METODY =============================================

    /***************************************************************************
     *
     */
    public NIOUtils()
    {
    }



//== ABSTRAKTNÍ METODY =========================================================
//== PŘÍSTUPOVÉ METODY VLASTNOSTÍ INSTANCÍ =====================================
//== OSTATNÍ NESOUKROMÉ METODY INSTANCÍ ========================================
//== SOUKROMÉ A POMOCNÉ METODY TŘÍDY ===========================================
//== SOUKROMÉ A POMOCNÉ METODY INSTANCÍ ========================================
//== INTERNÍ DATOVÉ TYPY =======================================================
//== TESTOVACÍ METODY A TŘÍDY ==================================================
//
//    /***************************************************************************
//     * Testovací metoda.
//     */
//    public static void test()
//    {
//        NIOUtils inst = new NIOUtils();
//    }
//    /** @param args Parametry příkazového řádku - nepoužívané. */
//    public static void main( String[] args )  {  test();  }
}
